home *** CD-ROM | disk | FTP | other *** search
Wrap
Text File | 1989-06-02 | 48.9 KB | 1,575 lines
-- card: 16339 from stack: in.1 -- bmap block id: 16385 -- flags: 0000 -- background id: 7836 -- name: MenuHandler ----- HyperTalk script ----- on closecard RemoveMenu set the name of btn 1 to "Install Menu" end closecard on InstallMenu global ExampleMenu put "(Disabled,Check,Test/A" into ExampleMenu MenuHandler "Add","Example",ExampleMenu MenuHandler "Disable","Go","Back" answer "Disabled HyperCard's 'go Back' menu item." end InstallMenu on RemoveMenu MenuHandler "Delete",Example MenuHandler "Enable","Go","Back" end RemoveMenu on domenu anItem global ExampleMenu, Disabled --anItem is the name of the menu item choosen -- HelpMenu is a list of items in my own help menu -- Disabled is the list of items that I have disabled if Disabled contains anItem then answer "HyperCard menu item "&anItem&" is disabled" with "OK" exit domenu else if ExampleMenu contains anItem then DoExample anItem -- see which item it is and do something else -- is an enable HyperCard item pass domenu -- pass it on down the line exit domenu end if end domenu on DoExample anItem global checked if anItem is "Check" then if checked is not true then MenuHandler "Mark","Example","Check",check put true into checked else MenuHandler "Mark","Example","Check",none put false into checked end if else if anItem is "Test" then answer "You have chosen the Test menu item." end if end DoExample -- part 3 (button) -- low flags: 00 -- high flags: A003 -- rect: left=76 top=298 right=320 bottom=176 -- title width / last selected line: 0 -- icon id / first selected line: 0 / 0 -- text alignment: 1 -- font id: 0 -- text size: 12 -- style flags: 0 -- line height: 16 -- part name: Install Menu ----- HyperTalk script ----- on mouseUp global ExampleMenu if the short name of me is "Install Menu" then InstallMenu -- see card script set the name of me to "Remove Menu" else RemoveMenu -- see card script set the name of me to "Install Menu" end if end mouseUp -- part 5 (field) -- low flags: 01 -- high flags: 2007 -- rect: left=18 top=32 right=288 bottom=480 -- title width / last selected line: 0 -- icon id / first selected line: 0 / 0 -- text alignment: 0 -- font id: 3 -- text size: 10 -- style flags: 0 -- line height: 13 -- part name: Documentation -- part 6 (button) -- low flags: 00 -- high flags: A003 -- rect: left=284 top=298 right=320 bottom=453 -- title width / last selected line: 0 -- icon id / first selected line: 0 / 0 -- text alignment: 1 -- font id: 0 -- text size: 12 -- style flags: 0 -- line height: 16 -- part name: Show LSC Source: part 1 ----- HyperTalk script ----- on mouseUp if the short name of me is "Show LSC Source: part 1" then set the visible of card field "source1" to true set the visible of card field "source2" to false set the name of me to "Show LSC Source: part 2" else if the short name of me is "Show LSC Source: part 2" then set the visible of card field "source2" to true set the visible of card field "source1" to false set the name of me to "Hide LSC Source" else set the visible of card field "source2" to false set the visible of card field "source1" to false set the name of me to "Show LSC Source: part 1" end if end mouseUp -- part 7 (field) -- low flags: 81 -- high flags: 0007 -- rect: left=18 top=31 right=289 bottom=492 -- title width / last selected line: 0 -- icon id / first selected line: 0 / 0 -- text alignment: 0 -- font id: 3 -- text size: 10 -- style flags: 0 -- line height: 13 -- part name: source1 -- part 8 (field) -- low flags: 81 -- high flags: 0007 -- rect: left=18 top=31 right=289 bottom=492 -- title width / last selected line: 0 -- icon id / first selected line: 0 / 0 -- text alignment: 0 -- font id: 3 -- text size: 10 -- style flags: 0 -- line height: 13 -- part name: source2 -- part contents for card part 5 ----- text ----- MenuHandler version 1.2d6 Roger Brown MenuHandler is an XCMD that gives you the ability to add and manipulate your own menus in a HyperCard stack. You can add and delete whole menus and items from menus. You can set and unset check marks. You can change the names of HyperCard's menus and items in them, but this is not advised because HyperCard handles its own menus in a special way. You can, however, hide HyperCard's menus or disable items in them using some features of this XCMD. To use this XCMD you will have to install your own DoMenu handler and maintain some special globals. These are explained below. Note: This version does not support hierarchical menus. Warning: Does not work with menu patches for large Radius screens. INVOKING MENUHANDLER HyperCard Syntax is: MenuHandler opcode,title,other things according to opcode it returns: error messages where the opcodes are: Add - adds a new menu parameters are title,item string,before title is the menu title items is string containing the menu items and their states in the normal Mac ToolBox format except for commas instead of semi-colons to make hypertalk level processing easier before is a string that names a menu to insert this one before (if empty, this menu goes at the end of the menu bar) Delete - deletes a menu and its handle parameter is title Hide - hides a menu but remembers it for later restoration parameter is title Show - restores a hidden menu parameter is title,afterMenu where after menu can be specified or the default is its original position Insert - inserts a menu item parameters are menu title, item name with format specifications, after item (number or name) Remove - removes a menu item parameters are menu title, item name or number Enable - enables a menu item parameters are menu title, item name or number A number of 0 enables the whole menu Disable - disables a menu item parameters are menu title, item name or number A number of 0 disables the whole menu Mark - checks an item parameters are menu title, item name or number and mark: none,command,check,diamond, or apple To compile: create a project with this and MacTraps. Build as code resource type XCMD named MenuHandler. EXAMPLE ex. MenuHandler "Add","Help","Introduction,(----,Glossary" SPECIAL GLOBALS A HyperCard global is maintained for every menu added through MenuHandler. The global has the same name as the menu. The menu items in a menu are found in a HyperCard item list contained in a global whose name is the name of the menu concatenated with the word "Menu" . This makes it easy to test if a doMenu call is for an added menu. ex. global HelpMenu = "Introduction,Getting Started,Glossary" An extra global is maintained that includes a list of all items that are currently disabled. These can be in new menus or in HyperCard's menus. This list is needed because some HyperCard menu actions can still proceed even when their menu items appear to be disabled. DOMENU HANDLER To use MenuHandler, you need to have your own DoMenu handler to see if the menu action is one of your own. If it isn't then you pass it on to HyperCard. Another reason to have your own DoMenu handler is to catch HyperCard menu items that you want to be disabled because HyperCard doesn't pay any attention to you if you make one of its items look disabled. A sample DoMenu handler is shown here and another is in the script of this stack. example: on domenu anItem global HelpMenu, Disabled --anItem is the name of the menu item choosen -- HelpMenu is a list of items in my own help menu -- Disabled is the list of items that I have disabled if Disabled contains anItem then answer "HyperCard menu item "&anItem&" is disabled"¬ with "OK" exit domenu else if HelpMenu contains anItem then DoMyHelp anItem -- see which item it is and do something else -- is an enable HyperCard item pass domenu - pass it on down the line exit domenu end if end domenu REVISION HISTORY 1.2d3 first public release version 1.2d4 fix problem with empty item list in AddAMenu 1.2d6 allow arbitrarily long menus in AddAMenu and InsertMenuItem -- part contents for card part 7 ----- text ----- /* MenuHandler1.2d6.c */ /* © Trustees of Dartmouth College */ /* written in LightSpeed C © Think Technologies, Inc */ /* by Roger Brown 7/21/88 Courseware Development group */ /* 5/5/89 version 1.2d6: Now handles arbitrarily long menu item lists in AddAMenu and InsertMenuItem. */ /* version 1.2d4 will bomb if you insert enough items to make the item list global greater than 255 chars. The Menu Manager dosen't care, just my UpdateItemGlobal procedure. */ /* 5/5/89 version 1.2d4: fix empty list problem in AddAMenu */ /* This is a HyperCard XFCN that handles menus in all sorts of ways. ********************************* *** Requires HC v1.2 or later *** ********************************* HyperCards Syntax is: MenuHandler message,title,other things according to message ex. MenuHandler "Add","Help","Introduction,(----,Glossary" returns: error messages where message is one of these opcodes: Add - adds a new menu parameters are title,item string,before title is the menu title items is string containing the menu items and their states in the normal Mac ToolBox format except for commas instead of semi-colons to make hypertalk level processing easier before is a string that names a menu to insert this one before (if empty, this menu goes at the end of the menu bar) Delete - deletes a menu and its handle parameter is title Hide - hides a menu but remembers it for later restoration parameter is title Show - restores a hidden menu parameter is title,afterMenu where after menu can be specified or the default is its original position Insert - inserts a menu item parameters are menu title, item name with format specifications, after item (number or name) Remove - removes a menu item parameters are menu title, item name or number Enable - enables a menu item parameters are menu title, item name or number A number of 0 enables the whole menu Disable - disables a menu item parameters are menu title, item name or number A number of 0 disables the whole menu Mark - checks an item parameters are menu title, item name or number and mark: none,command,check,diamond, or apple A HyperCard global is maintained for every menu added through MenuHandler. The menu items in a menu are found in a HyerCard item list in the global with the menu's name. This makes it easy to test if a doMenu call is for an added menu. ex. global HelpMenu = "Introduction,Getting Started,Glossary" An extra global is maintained that includes a list of all items that are currently disabled. These can be in new menus or in HyperCard's menus. This list is needed because some HyperCard menu actions can still proceed even when their menu items appear to be disabled. To compile: create a project with this and MacTraps. Build as code resource type XFCN named MenuHandler. */ #include "stddata_ctype.c" #include "strings.c" #include "MenuMgr.h" #include "HyperXCmd.h" #include "XCmdGlue.inc.c" #include "SetUpA4.h" #define FALSE 0 #define TRUE !FALSE typedef struct MenuRec { MenuHandle menuOH; int menuLeft; } MenuRec; typedef struct DynamicMenuList { /* this is actually a dynamic structure */ int lastMenu; int lastRight; int mbResID; MenuRec menu[64]; /* 64 is an aribtrary number, but plenty big */ } DynamicMenuList,*DMLPtr,**DMLHandle; char isNumber(); long ItemNumber(); MenuHandle GetHiddenMenu(); /* build a return result structure from a string */ ResultIs(paramPtr,theResult) XCmdBlockPtr paramPtr; char *theResult; { long len; Handle resultHandle; len = 1+strlen(theResult); resultHandle = NewHandle(len); BlockMove(theResult,*resultHandle,len); paramPtr->returnValue = resultHandle; } /* change a character into its upper case equivalent */ int toupper(c) char c; { return( (c>='a')&&(c<='z') ? (c-('a'-'A')) : c ); } /* change a string into its upper case equivalent */ ucase(s) char *s; { int i; char c; for (i=0;i<strlen(s);i++) { s[i] = toupper(s[i]); } } /* Get the number of HyperCard comma delimited items in string s. */ int NumHCItems(s) char *s; { int c,len,count,j; char temp[255]; long it; count = j = 0; len = strlen(s); for (c=0;c<len;c++) { if (s[c]==',') { count = count + 1; j = 0; } else { temp[j] = s[c]; j++; if (c==(len-1)) { /* last item, no comma */ count = count+1; break; } } } return count; } /* Get the number of HyperCard lines in string s. */ NumHCLines(source) char *source; { int i,c,len; len = strlen(source); c = 0; for (i=0;i<len;i++) { if (source[i]==13) c++; } if (source[i-1]!=13) c++; /* last line might not have CR */ return c; } /* Get HyperCard comma delimited item i from item list string inStr. Return it in outStr */ GetHCItem(inStr,i,outStr) char *inStr,*outStr; int i; { int c,len,count,j; char temp[255]; count = j = 0; len = strlen(inStr); for (c=0;c<len;c++) { if (inStr[c]==',') { count = count + 1; if (count==i) break; j = 0; } else { temp[j] = inStr[c]; j++; if (c==(len-1)) { /* last item, no comma */ count = count+1; break; } } } if (count < i) strcpy(temp,""); /* no item there */ temp[j] = 0; strcpy(outStr,temp); return; } /* get line number 'line' from source and return in dest */ GetHCLine(line,source,dest) int line; char *source,*dest; { int i,j,c,len; len = strlen(source); c = 1; i = 0; while (c<line) { if (source[i]==13) c++; i++; if (i>len) { /* out of range */ strcpy(dest,""); return; } } c = 0; for (j=i;j<len;j++) { *(dest+c) = source[j]; if (source[j]==13) break; /* line ended */ c++; } *(dest+c) = (char)0; } /* Test if item in itemStr is in container */ ItemInContainer(itemStr,container) char *itemStr,*container; { int c,len,j; char temp[255]; j = 0; len = strlen(container); for (c=0;c<len;c++) { if (container[c]==',') { if (strcmp(itemStr,temp)==0) return TRUE; j = 0; } else { temp[j] = container[c]; j++; temp[j] = 0; if (c==(len-1)) { /* last item, no comma */ break; } } } temp[j] = 0; if (strcmp(itemStr,temp)==0) return TRUE; return FALSE; } /* return false if s is not a valid integer, true and number if it is */ char isNumber(s,num) char *s; long *num; { /* s enters and exits in C format */ Str255 temp; int i,len; /* see if all characters are digits */ len = strlen(s); for (i=0;i<len;i++) { if (!isdigit(s[i])) return FALSE; } CtoPstr((char *)s); StringToNum(s,num); PtoCstr((char *)s); return TRUE; } /* Get the id of menu with title name. Also return its position in the menu list */ GetMenuID(name,pos) char *name; int *pos; /* position in menu list */ { DMLHandle theList; int lastMenu,i,j,numMenus; MenuRec anEntry; MenuHandle MHandle; Ptr MPtr; int *idPtr; Str255 title,uName; char len; strcpy(uName,name); /* copy name and change it to upper case */ ucase(name); theList = (DMLHandle)GetMenuBar(); /* get the menu list */ HLock((Handle)theList); lastMenu = (**theList).lastMenu; numMenus = lastMenu/6; for (i=0;i<numMenus;i++) { /* look at each menu in the list */ anEntry = (**theList).menu[i]; MHandle = anEntry.menuOH; MPtr = (Ptr)*MHandle; len = *(MPtr+14); for (j=0;j<len;j++) { /* get its title */ title[j] = *(MPtr+15+j); } title[j] = 0; ucase(title); if (strcmp(title,name)==0){ /* is it the same as name? */ idPtr = (int*)MPtr; HUnlock(theList); *pos = i+1; return *idPtr; /* return its id and position */ } } HUnlock(theList); return 0; /* not found */ } /* get item number of an item, given its name */ long ItemNumber(theMenu,theItem) MenuHandle theMenu; char *theItem; { int i,num; Str255 temp; ucase(theItem); num = 1+CountMItems(theMenu); for (i=1;i<num;i++) { /* scan all items in the menu */ GetItem(theMenu,i,temp); ucase(temp); PtoCstr((char *)temp); if (strcmp(temp,theItem)==0) /* found it */ return (long)i; } return (long)0; /* not found */ } /* Make the menus item list global agree with the menu. This completely rebuilds the global. */ UpdateItemGlobal(paramPtr,title) XCmdBlockPtr paramPtr; char *title; { #define kBlockSize 255 Str255 name,temp; int menuID,i,num; MenuHandle theMenu; long dummy,len; Handle theList; menuID = GetMenuID(title,&dummy); theMenu = GetMHandle(menuID); strcpy(name,title); strcat(name,"Menu"); CtoPstr((char *)name); theList = NewHandle(kBlockSize); if (theList == NULL) { ResultIs(paramPtr,"Out of memory in MenuHandler XCMD"); return; } HLock(theList); **theList = 0; len = kBlockSize; /* scan the menu list and pick up all item names */ num = 1+CountMItems(theMenu); for (i=1;i<num;i++) { GetItem(theMenu,i,temp); ucase(temp); PtoCstr((char *)temp); if (strlen(*theList)+strlen(temp) > len) { /* open up the list global */ len = len + kBlockSize; HUnlock(theList); SetHandleSize(theList,len); if (MemError()!=noErr) { ResultIs(paramPtr,"Out of memory in MenuHandler XCMD"); DisposHandle(theList); return; } HLock(theList); } strcat(*theList,temp); if (i<num-1) strcat(*theList,","); } SetGlobal(paramPtr,name,theList); DisposHandle(theList); } /* remove a menu from the disable global */ RemoveFromDisableGlobal(paramPtr,theMenu,theItem) XCmdBlockPtr paramPtr; MenuHandle theMenu; int theItem; { Handle theGlobal,theNewGlobal; int i,numItems; Str255 temp,itemName,handleStr; long len,tempLong; GetItem(theMenu,theItem,itemName); PtoCstr((char *)itemName); theGlobal = GetGlobal(paramPtr,"\pdisabled"); theNewGlobal = NewHandle(1); if (MemError()!=noErr) { ResultIs(paramPtr,"Out of Memory"); return; } MoveHHi(theGlobal); HLock(theGlobal); (**theNewGlobal) = 0; MoveHHi(theNewGlobal); HLock(theNewGlobal); strcpy(*theNewGlobal,""); /* scan the current global and rebuild with everything but this one */ numItems = NumHCItems(*theGlobal); for (i=0;i<numItems;i++) { GetHCItem(*theGlobal,i+1,temp); if (strcmp(itemName,temp)!=0) { /* not this one, put it back */ strcat(temp,","); len = GetHandleSize(theNewGlobal); len = len + (long)strlen(temp); HUnlock(theNewGlobal); SetHandleSize(theNewGlobal,len); if (MemError()!=noErr) { ResultIs(paramPtr,"Out of Memory"); return; } HLock(theNewGlobal); /* check for errors? */ strcat(*theNewGlobal,temp); } } /* set the new global value */ SetGlobal(paramPtr,"\pdisabled",theNewGlobal); HUnlock(theGlobal); HUnlock(theNewGlobal); DisposHandle(theGlobal); DisposHandle(theNewGlobal); } /* add a menu to the disable global */ AddToDisableGlobal(paramPtr,theMenu,theItem) XCmdBlockPtr paramPtr; MenuHandle theMenu; int theItem; { Handle theGlobal; Str255 numStr,temp,itemName; long len,tempLong; GetItem(theMenu,theItem,itemName); PtoCstr((char *)itemName); theGlobal = GetGlobal(paramPtr,"\pdisabled"); HLock(theGlobal); /* see if its already there */ if (ItemInContainer(itemName,*theGlobal)) { /* already stored */ HUnlock(theGlobal); DisposHandle(theGlobal); return; } /* tack it on the end */ len = GetHandleSize(theGlobal); len = len + (long)strlen(itemName) + 2; HUnlock(theGlobal); SetHandleSize(theGlobal,len); if (MemError()!=noErr) { ResultIs(paramPtr,"Out of Memory"); DisposHandle(theGlobal); return; } HLock(theGlobal); strcat(*theGlobal,itemName); strcat(*theGlobal,","); HUnlock(theGlobal); SetGlobal(paramPtr,"\pdisabled",theGlobal); DisposHandle(theGlobal); } /* add a menu to the menu bar */ pascal void AddAMenu(paramPtr) XCmdBlockPtr paramPtr; { int i,itsID,itemCount; Str255 titleStr,itemStr,beforeStr; Ptr theTitle,theItems; MenuHandle theMenu; int theMenuID,pos,beforeID; /* check parameter count */ if (paramPtr->paramCount < 3) { ResultIs(paramPtr,"Not enough parameters in Add."); return; } /* lock down the parameters so we can point to them */ for (i=1;i<paramPtr->paramCount;i++) { MoveHHi(paramPtr->params[i]); HLock (paramPtr->params[i]); } /* get the parameters */ theTitle = *(paramPtr->params[1]); theItems = *(paramPtr->params[2]); strcpy(titleStr,theTitle); /* see if we really need to do this */ if (GetMenuID(theTitle,&pos)!=0) { ResultIs(paramPtr,"Menu already shown."); for (i=1;i<paramPtr->paramCount;i++) HUnlock (paramPtr->params[i]); return; } /* get ready to talk to the menu manager */ CtoPstr((char *)titleStr); /* get an id for this menu */ itsID = 0; while (itsID<128) itsID = UniqueID('MENU'); /* create the menu and insert the items */ theMenu = NewMenu(itsID,titleStr); strcpy(itemStr," "); /* create menu with 1 blank item cuz AppendMenu */ CtoPstr((char*)itemStr); AppendMenu(theMenu,itemStr); /* can't handle a null string */ DelMenuItem(theMenu,1); /* now get rid of the blank menu item */ /* add all items by inserting - so we aren't constrained to 255 char limit */ itemCount = NumHCItems(theItems); for (i=0;i<itemCount;i++) { GetHCItem(theItems,i+1,itemStr); CtoPstr((char *)itemStr); InsMenuItem(theMenu,itemStr,i+2); } /* insert it as requested */ beforeID = 0; if (paramPtr->paramCount > 3) { strcpy(beforeStr,*(paramPtr->params[3])); beforeID = GetMenuID(beforeStr,&pos); } InsertMenu(theMenu,beforeID); /* update the menu bar */ DrawMenuBar(); /* create the menu global */ PtoCstr((char *)titleStr); UpdateItemGlobal(paramPtr,titleStr); /* clean up */ for (i=1;i<paramPtr->paramCount;i++) HUnlock (paramPtr->params[i]); return; } /* delete a menu from the menu bar and remove it from memory */ pascal void DeleteAMenu(paramPtr) XCmdBlockPtr paramPtr; { int i,itsID; Str255 titleStr,itemStr; Ptr theTitle,theItems; MenuHandle theMenu; int theMenuID,pos; Handle empty; /* check parameter count */ if (paramPtr->paramCount < 2) { ResultIs(paramPtr,"Not enough parameters in Delete."); return; } /* lock parameters down so we can point to them */ MoveHHi(paramPtr->params[1]); HLock (paramPtr->params[1]); theTitle = *(paramPtr->params[1]); strcpy(titleStr,theTitle); /* get the id of this menu */ theMenuID = GetMenuID(titleStr,&pos); if (theMenuID==NULL) { ResultIs(paramPtr,"MenuHandler error:Can't find menu to delete"); } else { /* get the menu and do the delete */ theMenu = GetMHandle(theMenuID); /* delete it from out save list if it is there */ RemoveFromSaveList(paramPtr,theMenu); /* remove its items from the disabled list */ for (i=0;i<CountMItems(theMenu);i++) RemoveFromDisableGlobal(paramPtr,theMenu,i+1); DeleteMenu(theMenuID); DisposeMenu(theMenu); DrawMenuBar(); /* clear the global with its name */ CtoPstr((char *)titleStr); empty = NewHandle(1); if (MemError()!=noErr) { ResultIs(paramPtr,"Out of Memory"); return; } HLock(empty); (**empty) = 0; HUnlock(empty); SetGlobal(paramPtr,titleStr,empty); DisposHandle(empty); } HUnlock (paramPtr->params[1]); return; } /* store a menu title,id, and position in a hidden HyperCard global */ StoreHiddenMenu(paramPtr,title,theMenu,pos) XCmdBlockPtr paramPtr; char *title; MenuHandle theMenu; int pos; { Handle theGlobal; Str255 numStr,temp; long len,tempLong; if (GetHiddenMenu(paramPtr,title,&tempLong)!=NULL) { return; /* already stored */ } theGlobal = GetGlobal(paramPtr,"\pXXMHLISTXX"); HLock(theGlobal); NumToString(theMenu,numStr); /* the menu handle */ PtoCstr((char *)numStr); strcpy(temp,title); /* the menu title */ strcat(temp,","); strcat(temp,numStr); strcat(temp,","); NumToString((long)pos,numStr); /* its position in the menu list */ PtoCstr((char *)numStr); strcat(temp,numStr); strcat(temp,"\15"); /* make it a HyperCard line */ /* add it to the end of the existing global */ len = GetHandleSize(theGlobal) + (long)strlen(temp) + 1; HUnlock(theGlobal); SetHandleSize(theGlobal,len); if (MemError()!=noErr) { ResultIs(paramPtr,"Out of Memory"); DisposHandle(theGlobal); return; } HLock(theGlobal); strcat(*theGlobal,temp); HUnlock(theGlobal); SetGlobal(paramPtr,"\pXXMHLISTXX",theGlobal); DisposHandle(theGlobal); } /* get a hidden menu's id from the hidden HC global. Return its handle and its position in the hidden list */ MenuHandle GetHiddenMenu(paramPtr,title,pos) XCmdBlockPtr paramPtr; char *title; long *pos; { Handle theGlobal; MenuHandle theMenu; int i,numLines; Str255 temp,name,idStr; /* get the hidden menu list */ theGlobal = GetGlobal(paramPtr,"\pXXMHLISTXX"); HLock(theGlobal); numLines = NumHCLines(*theGlobal); /* find it in the list */ for (i=0;i<numLines;i++) { GetHCLine(i+1,*theGlobal,temp); /* get the line for this menu */ GetHCItem(temp,1,name); if (strcmp(name,title)==0) { GetHCItem(temp,2,idStr); /* get its handle */ CtoPstr((char *)idStr); StringToNum(idStr,&theMenu); GetHCItem(temp,3,idStr); /* and its position */ CtoPstr((char *)idStr); StringToNum(idStr,pos); HUnlock(theGlobal); DisposHandle(theGlobal); return theMenu; } } HUnlock(theGlobal); DisposHandle(theGlobal); return NULL; } /* remove a menu from the list of saved menus */ RemoveFromSaveList(paramPtr,itsHandle) XCmdBlockPtr paramPtr; Handle itsHandle; { Handle theGlobal,theNewGlobal; MenuHandle theMenu; int i,numLines; Str255 temp,itemStr,handleStr; long len; /* scan the global and rebuild with all parts except this one */ theGlobal = GetGlobal(paramPtr,"\pXXMHLISTXX"); theNewGlobal = NewHandle(1); if (MemError()!=noErr) { ResultIs(paramPtr,"Out of Memory"); return; } HLock(theGlobal); HLock(theNewGlobal); strcpy(*theNewGlobal,""); NumToString((long)itsHandle,handleStr); PtoCstr((char *)handleStr); numLines = NumHCLines(*theGlobal); for (i=0;i<numLines;i++) { GetHCLine(i+1,*theGlobal,temp); GetHCItem(temp,2,itemStr); if (strcmp(itemStr,handleStr)!=0) { /* not this one, put it back */ strcat(temp,"\15"); len = GetHandleSize(theNewGlobal) + (long)strlen(temp); HUnlock(theNewGlobal); SetHandleSize(theNewGlobal,len); HLock(theNewGlobal); /* check for errors? */ strcat(*theNewGlobal,temp); } } SetGlobal(paramPtr,"\pXXMHLISTXX",theNewGlobal); HUnlock(theGlobal); HUnlock(theNewGlobal); DisposHandle(theGlobal); DisposHandle(theNewGlobal); } /* hide a menu but save it for later restoration */ /* store info in a special hypercard global */ pascal void HideMenu(paramPtr) XCmdBlockPtr paramPtr; { int i,itsID; Str255 titleStr,itemStr; Ptr theTitle,theItems; MenuHandle theMenu; int theMenuID,pos; /* check parameter count */ if (paramPtr->paramCount < 2) { ResultIs(paramPtr,"Not enough parameters in Hide."); return; } /* lock the parameters down so we can point to them */ MoveHHi(paramPtr->params[1]); HLock (paramPtr->params[1]); theTitle = *(paramPtr->params[1]); strcpy(titleStr,theTitle); theMenuID = GetMenuID(titleStr,&pos); if (theMenuID==NULL) ResultIs(paramPtr,"MenuHandler error:Can't find menu to hide"); else { /* delete the menu from the menu list but remember its name, handle and position */ theMenu = GetMHandle(theMenuID); DeleteMenu(theMenuID); StoreHiddenMenu(paramPtr,titleStr,theMenu,pos); DrawMenuBar(); } HUnlock (paramPtr->params[1]); return; } -- part contents for card part 8 ----- text ----- /* MenuHandler source: part 2 */ /* show a hidden menu */ pascal void ShowMenu(paramPtr) XCmdBlockPtr paramPtr; { int i,itsID; Str255 titleStr,itemStr,posStr; Ptr theTitle; MenuHandle theMenu; int theMenuID; long pos; /* check parameter count */ if (paramPtr->paramCount < 3) { ResultIs(paramPtr,"Not enough parameters in Show."); return; } /* lock parameters down so we can point to them */ for (i=1;i<3;i++) { MoveHHi(paramPtr->params[i]); HLock (paramPtr->params[i]); } theTitle = *(paramPtr->params[1]); strcpy(titleStr,theTitle); ucase(titleStr); strcpy(posStr,*paramPtr->params[2]); /* find the menu in the hidden list */ theMenu = GetHiddenMenu(paramPtr,titleStr,&pos); if (theMenu==NULL) ResultIs(paramPtr,"MenuHandler error:Can't find menu to show"); else { /* get its position */ if (strcmp(posStr,"")!=0) { if (!isNumber(posStr,&pos)) { pos = ItemNumber(theMenu,posStr); } } /* move it from hidden to shown */ InsertMenu(theMenu,(int)pos); RemoveFromSaveList(paramPtr,theMenu); DrawMenuBar(); } for (i=1;i<3;i++) HUnlock (paramPtr->params[i]); return; } /* insert an item into a menu */ pascal void InsertMenuItem(paramPtr) XCmdBlockPtr paramPtr; { int i,itsID,itemCount; Str255 titleStr,itemStr,afterStr; MenuHandle theMenu; int theMenuID,pos; long afterItem; Ptr theItems; /* check paramter count */ if (paramPtr->paramCount < 4) { ResultIs(paramPtr,"Not enough parameters in Insert."); return; } /* lock paramters down so we can point to them */ for (i=1;i<4;i++) { MoveHHi(paramPtr->params[i]); HLock (paramPtr->params[i]); } /* get the parameters */ strcpy(titleStr,*(paramPtr->params[1])); theItems = *(paramPtr->params[2]); strcpy(afterStr,*(paramPtr->params[3])); /* get the menu */ theMenuID = GetMenuID(titleStr,&pos); if (theMenuID==NULL) { ResultIs(paramPtr,"MenuHandler error:Can't find menu for insert"); } else { /* get its handle */ theMenu = GetMHandle(theMenuID); CtoPstr((char *)itemStr); /* Is it identified by name or number? */ if (!isNumber(afterStr,&afterItem)) afterItem = ItemNumber(theMenu,afterStr); /* add all items by inserting - so we aren't constrained to 255 char limit */ itemCount = NumHCItems(theItems); for (i=0;i<itemCount;i++) { GetHCItem(theItems,i+1,itemStr); CtoPstr((char *)itemStr); InsMenuItem(theMenu,itemStr,(int)(afterItem+i+2)); } /* register this change in the menu global */ UpdateItemGlobal(paramPtr,titleStr); } for (i=1;i<4;i++) HUnlock (paramPtr->params[i]); } /* remove an item from a menu */ pascal void RemoveMenuItem(paramPtr) XCmdBlockPtr paramPtr; { int i,itsID; Str255 titleStr,itemStr; Ptr theTitle,theItems; MenuHandle theMenu; int theMenuID; long theItem,pos; /* checkl parameter count */ if (paramPtr->paramCount < 3) { ResultIs(paramPtr,"Not enough parameters in Remove."); return; } /* lock the parameters so we can point to them */ for (i=1;i<3;i++) { MoveHHi(paramPtr->params[i]); HLock (paramPtr->params[i]); } /* get parameters */ strcpy(titleStr,*(paramPtr->params[1])); strcpy(itemStr,*(paramPtr->params[2])); /* get the menu */ theMenuID = GetMenuID(titleStr,&pos); if (theMenuID==NULL) ResultIs(paramPtr,"MenuHandler error:Can't find menu for removal request"); else { /* get its handle */ theMenu = GetMHandle(theMenuID); /* is it identified by name or number? */ if (!isNumber(itemStr,&theItem)) theItem = ItemNumber(theMenu,itemStr); /* delete it and update the menu global */ DelMenuItem(theMenu,(int)theItem); UpdateItemGlobal(paramPtr,titleStr); } for (i=1;i<3;i++) HUnlock (paramPtr->params[i]); } /* enable an item in a menu */ pascal void EnableMenuItem(paramPtr) XCmdBlockPtr paramPtr; { int i,itsID; Str255 titleStr,itemStr; Ptr theTitle,theItems; MenuHandle theMenu; int theMenuID,pos; long theItem; /* check parameter count */ if (paramPtr->paramCount < 3) { ResultIs(paramPtr,"Not enough parameters in Enable."); return; } /* lock down parameters so we can point to them */ for (i=1;i<3;i++) { MoveHHi(paramPtr->params[i]); HLock (paramPtr->params[i]); } /* get parameters */ strcpy(titleStr,*(paramPtr->params[1])); strcpy(itemStr,*(paramPtr->params[2])); /* get the menu */ theMenuID = GetMenuID(titleStr,&pos); if (theMenuID==NULL) ResultIs(paramPtr,"MenuHandler error:Can't find menu for enable request"); else { /* get its handle */ theMenu = GetMHandle(theMenuID); /* is it identified by name or number? */ if (!isNumber(itemStr,&theItem)) { theItem = ItemNumber(theMenu,itemStr); if (theItem==0L) { /* none to disable */ ResultIs(paramPtr,"Invalid item number in enable"); for (i=1;i<3;i++) HUnlock (paramPtr->params[i]); return; } } EnableItem(theMenu,(int)theItem); if ((int)theItem != 0) { /* update disable global */ RemoveFromDisableGlobal(paramPtr,theMenu,(int)theItem); } else { /* remove all items in it from the disable global */ for (i=0;i<CountMItems(theMenu);i++) { RemoveFromDisableGlobal(paramPtr,theMenu,(int)i+1); } } } for (i=1;i<3;i++) HUnlock (paramPtr->params[i]); } /* disable a menu item */ pascal void DisableMenuItem(paramPtr) XCmdBlockPtr paramPtr; { int i,itsID; Str255 titleStr,itemStr; Ptr theTitle,theItems; MenuHandle theMenu; int theMenuID,pos; long theItem; /* check parameter count */ if (paramPtr->paramCount < 3) { ResultIs(paramPtr,"Not enough parameters in Disable."); return; } /* lock down parameters so we can point to them */ for (i=1;i<3;i++) { MoveHHi(paramPtr->params[i]); HLock (paramPtr->params[i]); } /* get parameters */ strcpy(titleStr,*(paramPtr->params[1])); strcpy(itemStr,*(paramPtr->params[2])); /* get the menu */ theMenuID = GetMenuID(titleStr,&pos); if (theMenuID==NULL) ResultIs(paramPtr,"MenuHandler error:Can't find menu for disable request"); else { /* get its handle */ theMenu = GetMHandle(theMenuID); /* is it identified by name or number? */ if (!isNumber(itemStr,&theItem)) { theItem = ItemNumber(theMenu,itemStr); if (theItem==0L) { /* none to disable */ ResultIs(paramPtr,"Invalid item number in disable"); for (i=1;i<3;i++) HUnlock (paramPtr->params[i]); return; } } /* disable it */ DisableItem(theMenu,(int)theItem); /* update the disabled menu global */ if ((int)theItem != 0) { AddToDisableGlobal(paramPtr,theMenu,(int)theItem); } else { for (i=0;i<CountMItems(theMenu);i++) { AddToDisableGlobal(paramPtr,theMenu,(int)i+1); } } } for (i=1;i<3;i++) HUnlock (paramPtr->params[i]); } /* mark a menu item */ pascal void MarkMenuItem(paramPtr) XCmdBlockPtr paramPtr; { int i,itsID; Str255 titleStr,itemStr,markStr; Ptr theTitle,theItems; MenuHandle theMenu; int theMenuID,pos; long theItem; char markChar; /* checl parameter count */ if (paramPtr->paramCount < 4) { ResultIs(paramPtr,"Not enough parameters in Mark."); return; } /* lock down the parameters so we can point to them */ for (i=1;i<4;i++) { MoveHHi(paramPtr->params[i]); HLock (paramPtr->params[i]); } /* get parameters */ strcpy(titleStr,*(paramPtr->params[1])); strcpy(itemStr,*(paramPtr->params[2])); /* get the menu */ theMenuID = GetMenuID(titleStr,&pos); if (theMenuID==NULL) ResultIs(paramPtr,"MenuHandler error:Can't find menu for mark request"); else { /* get its handle */ theMenu = GetMHandle(theMenuID); /* is it identified by name or number? */ if (!isNumber(itemStr,&theItem)) { theItem = ItemNumber(theMenu,itemStr); if (theItem==0L) { /* none to mark */ ResultIs(paramPtr,"Invalid item number in mark"); for (i=1;i<4;i++) HUnlock (paramPtr->params[i]); return; } } /* decode the mark parameter */ strcpy(markStr,*(paramPtr->params[3])); ucase(markStr); if (strcmp(markStr,"NONE")==0) markChar = noMark; else if (strcmp(markStr,"COMMAND")==0) markChar = commandMark; else if (strcmp(markStr,"CHECK")==0) markChar = checkMark; else if (strcmp(markStr,"DIAMOND")==0) markChar = diamondMark; else if (strcmp(markStr,"APPLE")==0) markChar = appleMark; else { ResultIs(paramPtr,"Unknown mark type."); return; } /* set the mark */ SetItemMark(theMenu,theItem,markChar); } for (i=1;i<4;i++) HUnlock (paramPtr->params[i]); } /* XCMD entry point */ pascal void main(paramPtr) XCmdBlockPtr paramPtr; /* this is the entry point for the XFCN */ { Handle taskHandle,portHandle; Str255 temp; RememberA0(); SetUpA4(); /* use global variables */ /* get the opcode */ taskHandle = paramPtr->params[0]; ucase(*taskHandle); /* branch on the opcode */ if (strcmp(*taskHandle,"ADD")==0) AddAMenu(paramPtr); else if (strcmp(*taskHandle,"DELETE")==0) DeleteAMenu(paramPtr); else if (strcmp(*taskHandle,"HIDE")==0) HideMenu(paramPtr); else if (strcmp(*taskHandle,"SHOW")==0) ShowMenu(paramPtr); else if (strcmp(*taskHandle,"INSERT")==0) InsertMenuItem(paramPtr); else if (strcmp(*taskHandle,"REMOVE")==0) RemoveMenuItem(paramPtr); else if (strcmp(*taskHandle,"ENABLE")==0) EnableMenuItem(paramPtr); else if (strcmp(*taskHandle,"DISABLE")==0) DisableMenuItem(paramPtr); else if (strcmp(*taskHandle,"MARK")==0) MarkMenuItem(paramPtr); else { strcpy(temp,"MenuHandler Error: unknown message "); strcat(temp,*taskHandle); ResultIs(paramPtr,temp); } RestoreA4(); return; }